package itbour.onetouchshow.widget.clip;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;

import com.google.zxing.Result;
import com.google.zxing.ResultPoint;

import itbour.onetouchshow.activity.video.clip.ClipActivity;
import itbour.onetouchshow.utils.CommonUtils;
import itbour.onetouchshow.utils.DecodeImageQRCode;
import itbour.onetouchshow.utils.ImageTools;
import itbour.onetouchshow.utils.L_;


/**
 * @author king
 * @time 2014-6-18
 */
public class ClipZoomImageView extends AppCompatImageView implements View.OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener {

    // 裁剪 的边距
//	private static final int BORDERDISTANCE = ClipView.BORDERDISTANCE;

    // 默认最大倍数
    public static final float DEFAULT_MAX_SCALE = 4.0f;
    // 放大倍数居中
    public static final float DEFAULT_MID_SCALE = 2.0f;
    // 最小放大倍数
    public static final float DEFAULT_MIN_SCALE = 1.0f;
    private static final java.lang.String TAG = "ClipZoomImageView";
    private final Matrix baseMatrix = new Matrix();
    private final Matrix drawMatrix = new Matrix();
    private final Matrix suppMatrix = new Matrix();
    private final RectF displayRect = new RectF();
    private final float[] matrixValues = new float[9];
    // 裁剪区域宽高
    public float clipWidth;
    public float clipHeight;
    //当是二维码的时候执行的逻辑
    public float qrCodeScale;
    public float ratiox;
    public float ratioy;
    public boolean ivIsQrCode;
    private float minScale = DEFAULT_MIN_SCALE;
    private float midScale = DEFAULT_MID_SCALE;
    private float maxScale = DEFAULT_MAX_SCALE;
    private MultiGestureDetector multiGestureDetector;
    // 裁剪偏移
//    public float offx;
//    public float offy;
    private boolean isJusted;
//    private Dialog dialog;


    public ClipZoomImageView(Context context) {
        this(context, null);
    }

    public ClipZoomImageView(Context context, AttributeSet attr) {
        this(context, attr, 0);
    }

    public ClipZoomImageView(Context context, AttributeSet attr, int defStyle) {
        super(context, attr, defStyle);

        super.setScaleType(ScaleType.MATRIX);

        setOnTouchListener(this);

        multiGestureDetector = new MultiGestureDetector(context);
//        dialog = DialogUtils.webLoadingDialog(getContext(), "正在识别二维码...", false);
    }

    public void setQrCodeScale(float qrCodeScale) {
        this.qrCodeScale = qrCodeScale;
    }

    public void setRatiox(float ratiox) {
        this.ratiox = ratiox;
    }

    public void setRatioy(float ratioy) {
        this.ratioy = ratioy;
    }

    public void setIvIsQrCode(boolean ivIsQrCode) {
        this.ivIsQrCode = ivIsQrCode;
    }

    public void setQrCodeParams(boolean ivIsQrCode, float qrCodeScale, float ratiox, float ratioy) {
        setQrCodeScale(qrCodeScale);
        setIvIsQrCode(ivIsQrCode);
        setRatiox(ratiox);
        setRatioy(ratioy);

    }

    // min scale 懒加载  传入的是原图 根据当前显示区域来计算矩阵的缩放
    public float getMinScale() {

        float scale = 1.0f;
        Drawable d = getDrawable();
        if (d == null) {
            minScale = scale;
            return scale;
        }
//        // 绘制的宽高
        int drawableWidth = d.getIntrinsicWidth();
        int drawableHeight = d.getIntrinsicHeight();
        float scaleW = clipWidth * 1.0f / drawableWidth;
        float scaleH = clipHeight * 1.0f / drawableHeight;
        // 取最大的比例, 确保最小的边也能填充完整
        scale = scaleW < scaleH ? scaleW : scaleH;
        minScale = scale;
        return scale;
    }

    /**
     *
     */
    private void configPosition() {
        super.setScaleType(ScaleType.MATRIX);
        Drawable d = getDrawable();
        if (d == null) {
            return;
        }

        //屏幕宽高
        final float viewWidth = getWidth();
        final float viewHeight = getHeight();
        //图片宽高
        final int drawableWidth = d.getIntrinsicWidth();
        final int drawableHeight = d.getIntrinsicHeight();
        float scale = 1.0f;


        scale = getMinScale();
        baseMatrix.reset();
        baseMatrix.postScale(scale, scale);
        // 调整图片位置 这样是为了让图片居中
        float offsetX = (viewWidth - drawableWidth * scale) * 0.5f;
        float offsetY = (viewHeight - drawableHeight * scale) * 0.5f;


        L_.i(TAG, "zoomImgbaseMatrix===offsetX===" + offsetX
                + "offsetY===" + offsetY + "scale===" + scale + "viewWidth==="
                + viewWidth + "viewHeight===" + viewHeight + "drawableWidth===" + drawableWidth + "drawableHeight===" + drawableHeight);
        baseMatrix.postTranslate(offsetX, offsetY);

        //每次进来重置单边填充逻辑和supportMatrix
        resetMatrix();

        if (ivIsQrCode) {
            Drawable drawable = getDrawable();
            Bitmap bitmap = ImageTools.drawableToBitmap(drawable);
            //第一次用总图 手指抬起 用裁切
            boolean isWork = jugleNowInMaskImageQrCodeIsWork(bitmap);

            //目前的bug 如果图片比手机小 那么scale 为0!  如果不起作用 就不执行缩放逻辑!


            if (isWork) {
                isQRcodeLogic();
//              放大后后再通过模板判断一遍
                Bitmap clip = clip();
                boolean isWorkClip = jugleNowInMaskImageQrCodeIsWork(clip);
//                设置当前二维码是否有效
                upDataQrCodeIsWork(isWork && isWorkClip);
                scale = getScale();
                upScaleToClipAct(scale);
            } else {
                upDataQrCodeIsWork(isWork);
            }
        }

        isJusted = true;
    }

    public float[] jugleQRCodeIsWork(Context context, final Bitmap bitmap) {

        final float[] qrCodeArr = {0.0f, 0.0f, 0.0f};
        DecodeImageQRCode coder = new DecodeImageQRCode(context);

        coder.decodeBitmap(bitmap, new DecodeImageQRCode.DecodeResultInteface() {
            @Override
            public void decodeResult(Result result) {
                if (result != null) {
                    ResultPoint[] pointA = result.getResultPoints();
                    Log.e("二维码扫描结果", result.getText());

                    for (ResultPoint point : result.getResultPoints()) {
                        Log.e("二维码扫描的点为 ", "" + point.getX() + point.getY());
                    }
                    float min_x = bitmap.getWidth();
                    float min_y = bitmap.getHeight();

                    ResultPoint patt1 = result.getResultPoints()[0];
                    ResultPoint patt2 = result.getResultPoints()[1];

                    float www = (patt1.getX() - patt2.getX());
                    if (www < 0) {
                        www = -www;
                    }
                    float hhh = (patt1.getY() - patt2.getY());
                    if (hhh < 0) {
                        hhh = -hhh;
                    }

                    if (www < hhh) {
                        www = hhh;
                    }

                    float width = www;

                    for (ResultPoint pattern : result.getResultPoints()) {
                        float min_xt = pattern.getX();
                        float min_yt = pattern.getY();
                        if (min_xt < min_x) {
                            min_x = min_xt;
                        }

                        if (min_yt < min_y) {
                            min_y = min_yt;
                        }
                    }

                    float scale;
                    if (bitmap.getWidth() > bitmap.getHeight()) {
                        scale = bitmap.getHeight() / (width * 7 / 5);
                    } else {
                        scale = bitmap.getWidth() / (width * 7 / 5);
                    }

                    float leftRatioy;
                    float leftRatiox;

                    leftRatioy = (min_y + width / 2) / bitmap.getHeight();
                    leftRatiox = (min_x + width / 2) / bitmap.getWidth();


                    Log.e("计算比例为 ", "width" + width + "结果" + "scale" + scale + "ratiox" + leftRatiox + "ratioy" + leftRatioy);
                    //二维码有效  width  scale 当前基础缩放几倍 ratioxX二维码的中心点在 图片中的比例 ratioY在图片中心点的位置

                    qrCodeArr[0] = scale;
                    qrCodeArr[1] = leftRatiox;
                    qrCodeArr[2] = leftRatioy;

                } else {
                    //二维码无效
                    Log.e("未扫描到", "结果");
                }

                L_.i(TAG, "zxingcurrtName===" + Thread.currentThread().getName());
//                if(dialog!=null){
//                    dialog.dismiss();
//                }
            }
        });
        return qrCodeArr;
    }

    //true 有效 false无效
    public boolean jugleNowInMaskImageQrCodeIsWork(Bitmap bitmap) {
        float[] floats = jugleQRCodeIsWork(getContext(), bitmap);
        boolean qrCodeNotWork = CommonUtils.floatEqual(floats[0], 0.0f) && CommonUtils.floatEqual(floats[1], 0.0f) && CommonUtils.floatEqual(floats[2], 0.0f);
        if (!qrCodeNotWork) {
            setQrCodeParams(true, floats[0], floats[1], floats[2]);

            L_.i(TAG, "二维码有效!!");
        } else {
            L_.i(TAG, "二维码无效!!");
        }
        return !qrCodeNotWork;
    }

    //当是二维码的时候 执行的平移和缩放的逻辑
    public void isQRcodeLogic() {
        //更新当前图片的分辨率
        //屏幕宽高
        final float viewWidth = getWidth();
        final float viewHeight = getHeight();
        Drawable d = getDrawable();
        if (d == null) {
            return;
        }
        //图片宽高
        final int drawableWidth = d.getIntrinsicWidth();
        final int drawableHeight = d.getIntrinsicHeight();
        float mineScale = getMinScale();

        suppMatrix.postScale(qrCodeScale, qrCodeScale);


        float resetOffsetX = -(viewWidth - drawableWidth * mineScale) * 0.5f * qrCodeScale;
        float resetOffsetY = -(viewHeight - drawableHeight * mineScale) * 0.5f * qrCodeScale;

        //再把屏幕左上角的 0 0  这一步之后 中心点位于屏幕的左上角 0 0
        float supOffsetX = -drawableWidth * mineScale * qrCodeScale * ratiox;
        float supOffsetY = -drawableHeight * mineScale * qrCodeScale * ratioy;
        //将左上角的中心点移动到屏幕的中心点
        float offsetX = resetOffsetX + supOffsetX + viewWidth * 0.5f;
        float offsetY = resetOffsetY + supOffsetY + viewHeight * 0.5f;

        suppMatrix.postTranslate(offsetX, offsetY);


        setImageMatrix(getDisplayMatrix());
        //baseMatrix的为1.0f基准倍数

    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Log.d("---debug", "onTouch: v height width = " + v.getHeight() + v.getWidth());
        return multiGestureDetector.onTouchEvent(event);
    }

    public void setClipWH(int width, int height) {
        this.clipWidth = width;
        this.clipHeight = height;
    }

    /**
     * 更新现在的缩放比用于计算当前像素
     *
     * @param scale
     */
    private void upScaleToClipAct(float scale) {
        Context context = getContext();
        if (context instanceof ClipActivity) {
//            ClipActivity clipActivity = (ClipActivity) context;
//
//            clipActivity.setIsFitStatus(scale);
        }
    }

    /**
     * 更新当前二维码 是否有效
     *
     * @param isWork
     */
    private void upDataQrCodeIsWork(boolean isWork) {
        Context context = getContext();
        if (context instanceof ClipActivity) {
            ClipActivity clipActivity = (ClipActivity) context;

//            clipActivity.setQrCodeIsWork(isWork);
        }

    }

    @TargetApi(VERSION_CODES.JELLY_BEAN)
    private void postOnAnimation(View view, Runnable runnable) {
        if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
            view.postOnAnimation(runnable);
        } else {
            view.postDelayed(runnable, 16);
        }
    }

    /**
     * Returns the current scale value
     *
     * @return float - current scale value
     */
    public final float getScale() {
        suppMatrix.getValues(matrixValues);
        return matrixValues[Matrix.MSCALE_X];
    }

    @Override
    public void onGlobalLayout() {
        if (isJusted) {
            return;
        }
        configPosition();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @SuppressWarnings("deprecation")
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getViewTreeObserver().removeGlobalOnLayoutListener(this);
    }

    /**
     * Helper method that simply checks the Matrix, and then displays the result
     */
    private void checkAndDisplayMatrix() {
        checkMatrixBounds();
        setImageMatrix(getDisplayMatrix());
    }

    private void checkMatrixBounds() {
        final RectF rect = getDisplayRect(getDisplayMatrix());
        if (null == rect) {
            return;
        }

        float deltaX = 0, deltaY = 0;
        final float viewWidth = getWidth();
        final float viewHeight = getHeight();
        // 移动时对坐标进行控制防止图片超出裁剪区域
        if (rect.top > (viewHeight - clipHeight) / 2) {
            deltaY = (viewHeight - clipHeight) / 2 - rect.top;
        }
        if (rect.bottom < (viewHeight + clipHeight) / 2) {
            deltaY = (viewHeight + clipHeight) / 2 - rect.bottom;
        }
        if (rect.left > (viewWidth - clipWidth) / 2) {
            deltaX = (viewWidth - clipWidth) / 2 - rect.left;
        }
        if (rect.right < (viewWidth + clipWidth) / 2) {
            deltaX = (viewWidth + clipWidth) / 2 - rect.right;
        }
        // Finally actually translate the matrix
        suppMatrix.postTranslate(deltaX, deltaY);
    }

    /**
     * Helper method that maps the supplied Matrix to the current Drawable
     *
     * @param matrix - Matrix to map Drawable against
     * @return RectF - Displayed Rectangle
     */
    private RectF getDisplayRect(Matrix matrix) {
        Drawable d = getDrawable();
        if (null != d) {
            displayRect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
            matrix.mapRect(displayRect);
            return displayRect;
        }

        return null;
    }

    /**
     * Resets the Matrix back to FIT_CENTER, and then displays it.s
     */
    private void resetMatrix() {
        if (suppMatrix == null) {
            return;
        }
        suppMatrix.reset();
        setImageMatrix(getDisplayMatrix());
    }

    //setImageMarix  真正绘制的逻辑
    protected Matrix getDisplayMatrix() {
        drawMatrix.set(baseMatrix);//将baseMatrix数组的值 赋值给drawMatrix
        drawMatrix.postConcat(suppMatrix);//等价于先处理drawMatrix 再处理
        return drawMatrix;
    }

    /**
     * 裁剪图片
     *
     * @return
     */
    public Bitmap clip() {
//        DisplayMetrics dm = getResources().getDisplayMetrics();
//        int windowHeight = dm.heightPixels;
//        int windowWidth = dm.widthPixels;


        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_4444);
        int byteCount = bitmap.getByteCount();
        L_.i("byteCount===" + byteCount);
        Canvas canvas = new Canvas(bitmap);
        draw(canvas);
        minScale = getScale();
        int x = (int) (getWidth() - clipWidth) / 2;
        int y = (int) (getHeight() - clipHeight) / 2;

        if (x < 0) {
            x = 0;
        }
        if (y < 0) {
            y = 0;
        }


//        Bitmap bitmaps = BitMapUtils.comp(Bitmap.createBitmap(bitmap, x, y, (int) clipWidth, (int) clipHeight));

        return bitmap;
    }

    public Bitmap getOriangeBitMap() {

        return ((BitmapDrawable) getDrawable()).getBitmap();
    }

    private class MultiGestureDetector extends GestureDetector.SimpleOnGestureListener implements
            OnScaleGestureListener {

        private final ScaleGestureDetector scaleGestureDetector;
        private final GestureDetector gestureDetector;
        private final float scaledTouchSlop;

        private VelocityTracker velocityTracker;
        private boolean isDragging;

        private float lastTouchX;
        private float lastTouchY;
        private float lastPointerCount;

        public MultiGestureDetector(Context context) {
            scaleGestureDetector = new ScaleGestureDetector(context, this);

            gestureDetector = new GestureDetector(context, this);
            gestureDetector.setOnDoubleTapListener(this);

            final ViewConfiguration configuration = ViewConfiguration.get(context);
            scaledTouchSlop = configuration.getScaledTouchSlop();
        }

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float scale = getScale();
            // 重新计算最小缩放倍数
//            minScale = getMinScale();
            minScale = 1.0f;
            float scaleFactor = detector.getScaleFactor();
            L_.i(TAG, "onScale: scale minscale scaleFactor" + scale + minScale + scaleFactor);
            L_.i(TAG, "onScale: clipWidth =" + clipWidth);
            L_.i(TAG, "onScale: clipHeight =" + clipHeight);

            upScaleToClipAct(scale);


            if (getDrawable() != null && ((scale < maxScale && scaleFactor > 1.0f) || (scale > minScale && scaleFactor < 1.0f))) {
                if (scaleFactor * scale < minScale) {
                    scaleFactor = minScale / scale;
                }
                if (scaleFactor * scale > maxScale) {
                    scaleFactor = maxScale / scale;
                }
                suppMatrix.postScale(scaleFactor, scaleFactor, getWidth() / 2, getHeight() / 2);
                checkAndDisplayMatrix();


            }
            return true;
        }

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
            checkAndDisplayMatrix();
        }

        public boolean onTouchEvent(MotionEvent event) {
            if (gestureDetector.onTouchEvent(event)) {
                return true;
            }

            scaleGestureDetector.onTouchEvent(event);

            /*
             * Get the center x, y of all the pointers
             */
            float x = 0, y = 0;
            final int pointerCount = event.getPointerCount();
            for (int i = 0; i < pointerCount; i++) {
                x += event.getX(i);
                y += event.getY(i);
            }
            x = x / pointerCount;
            y = y / pointerCount;

            /*
             * If the pointer count has changed cancel the drag
             */
            if (pointerCount != lastPointerCount) {
                isDragging = false;
                if (velocityTracker != null) {
                    velocityTracker.clear();
                }
                lastTouchX = x;
                lastTouchY = y;
            }
            lastPointerCount = pointerCount;

            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (velocityTracker == null) {
                        velocityTracker = VelocityTracker.obtain();
                    } else {
                        velocityTracker.clear();
                    }
                    velocityTracker.addMovement(event);

                    lastTouchX = x;
                    lastTouchY = y;
                    isDragging = false;
                    break;

                case MotionEvent.ACTION_MOVE: {
                    final float dx = x - lastTouchX, dy = y - lastTouchY;

                    if (isDragging == false) {
                        // Use Pythagoras to see if drag length is larger than
                        // touch slop
                        isDragging = Math.sqrt((dx * dx) + (dy * dy)) >= scaledTouchSlop;
                    }

                    if (isDragging) {
                        if (getDrawable() != null) {
                            suppMatrix.postTranslate(dx, dy);
                            checkAndDisplayMatrix();
                        }

                        lastTouchX = x;
                        lastTouchY = y;

                        if (velocityTracker != null) {
                            velocityTracker.addMovement(event);
                        }
                    }

                    L_.i(TAG, "isDraggingtrue===dx===" + dx + "dy===" + dy);
                    break;
                }
                case MotionEvent.ACTION_UP:
                    L_.i(TAG, "ACTION_UP===clipWidth" + clipWidth + "clipHeight===" + clipHeight);
                    L_.i(TAG, "zxingcurrtACTION_UP");
                    //如果是二维码节点 根据蒙版裁切 看能不能识别 如果识别二维码未完成 禁止拖动
                    if (ivIsQrCode) {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                Bitmap clip = clip();
                                boolean isWork = jugleNowInMaskImageQrCodeIsWork(clip);
                                upDataQrCodeIsWork(isWork);
                            }
                        }).start();


                    }


                    break;

                case MotionEvent.ACTION_CANCEL:
                    lastPointerCount = 0;
                    if (velocityTracker != null) {
                        velocityTracker.recycle();
                        velocityTracker = null;
                    }
                    break;
            }

            return true;
        }


        /**
         * 双击时执行动画  post动画后执行run
         *
         * @param event
         * @return
         */
        @Override
        public boolean onDoubleTap(MotionEvent event) {
            try {
                float scale = getScale();
                float x = getWidth() / 2;
                float y = getHeight() / 2;

                if (scale < midScale) {
                    post(new AnimatedZoomRunnable(scale, midScale, x, y));
                } else if ((scale >= midScale) && (scale < maxScale)) {
                    post(new AnimatedZoomRunnable(scale, maxScale, x, y));
                } else {
                    post(new AnimatedZoomRunnable(scale, minScale, x, y));
                }
            } catch (Exception e) {
                // Can sometimes happen when getX() and getY() is called
            }

            return true;
        }
    }

    private class AnimatedZoomRunnable implements Runnable {
        // These are 'postScale' values, means they're compounded each iteration
        static final float ANIMATION_SCALE_PER_ITERATION_IN = 1.07f;
        static final float ANIMATION_SCALE_PER_ITERATION_OUT = 0.93f;

        private final float focalX, focalY;
        private final float targetZoom;
        private final float deltaScale;

        public AnimatedZoomRunnable(final float currentZoom, final float targetZoom,
                                    final float focalX, final float focalY) {
            this.targetZoom = targetZoom;
            this.focalX = focalX;
            this.focalY = focalY;

            if (currentZoom < targetZoom) {
                deltaScale = ANIMATION_SCALE_PER_ITERATION_IN;
            } else {
                deltaScale = ANIMATION_SCALE_PER_ITERATION_OUT;
            }
        }

        public void run() {
            suppMatrix.postScale(deltaScale, deltaScale, focalX, focalY);
            checkAndDisplayMatrix();

            final float currentScale = getScale();

            if (((deltaScale > 1f) && (currentScale < targetZoom))
                    || ((deltaScale < 1f) && (targetZoom < currentScale))) {
                // We haven't hit our target scale yet, so post ourselves
                // again
                postOnAnimation(ClipZoomImageView.this, this);

            } else {
                // We've scaled past our target zoom, so calculate the
                // necessary scale so we're back at target zoom
                final float delta = targetZoom / currentScale;
                suppMatrix.postScale(delta, delta, focalX, focalY);
                checkAndDisplayMatrix();
            }
        }
    }

    class UpQrCodeIsWorkTask extends AsyncTask<Void, Integer, Integer> {

        UpQrCodeIsWorkTask(Context context) {

        }

        public UpQrCodeIsWorkTask() {
        }

        /**
         * 运行在UI线程中，在调用doInBackground()之前执行
         */
        @Override
        protected void onPreExecute() {

        }

        /**
         * 后台运行的方法，可以运行非UI线程，可以执行耗时的方法
         */
        @Override
        protected Integer doInBackground(Void... params) {


            return null;

        }

        /**
         * 运行在ui线程中，在doInBackground()执行完毕后执行
         */
        @Override
        protected void onPostExecute(Integer integer) {
//            Toast.makeText(context,"执行完毕",Toast.LENGTH_SHORT).show();
        }

        /**
         * 在publishProgress()被调用以后执行，publishProgress()用于更新进度
         */
        @Override
        protected void onProgressUpdate(Integer... values) {

        }
    }

}
